//
//  PhotoManager.swift
//  ClockWidget
//
//  Created by TSYH on 2024/3/12.
//

import Photos
import PhotosUI
import Kingfisher

public class PhotoManager: NSObject {
    public enum PickerPushType {
        case push
        case present
    }
    public class Config {
        public var type: PickerPushType = .present
        public var limit: Int = 1
        public var shouldCrop: Bool = false
        public var cropRatio: CGFloat = 1.0
        public var cropHandler: ((PHPickerViewController, UIImage) -> Void)?
        public var completionHandler: (([UIImage]) -> Void)?
    }
    
    public static let shared = PhotoManager()
    lazy var config = Config()
    lazy var multiTaskQueue = DispatchQueue(label: "multi_image_download_task_queue")
    lazy var queue = DispatchQueue(label: "queue_image_download_task")
    
    public lazy var cancelImportTask = false
    var importingHandler: (() -> Void)?
    var importCompletionHandler: ImportCompletionHandler?
    
    var currentImportProgress: Progress?
}

public extension PhotoManager {
    /// 打开相册
    func openPhotoLibrary(from viewController: UIViewController,
                          authorHandler: ((PHAuthorizationStatus) -> Void)?,
                          configHandler: ((Config) -> Void)?) {
        let c = Config()
        configHandler?(c)
        config = c
        
        importCompletionHandler = nil
        
        let imageHandler = { [weak self] in
            guard let self = self else { return }
            
            var configuration = PHPickerConfiguration(photoLibrary: .shared())
            let filter = PHPickerFilter.images
            configuration.filter = filter
            configuration.selectionLimit = self.config.limit
            
            let vc = PHPickerViewController(configuration: configuration)
            vc.view.tintColor = UIColor.systemBlue
            vc.view.backgroundColor = .white
            vc.delegate = self
            
            if self.config.type == .present {
                vc.modalPresentationStyle = .fullScreen
                viewController.present(vc, animated: true)
            } else {
                viewController.navigationController?.pushViewController(vc, animated: true)
            }
        }
        
        handlerAfterAuthorization { status in
            authorHandler?(status)
            if status == .authorized || status == .limited {
                imageHandler()
            }
        }
    }
    /// 写入相册
    func writeToLibrary(data: Data,
                        completion: ((Bool) -> Void)?) {
        PHPhotoLibrary.shared().performChanges {
            let request = PHAssetCreationRequest.forAsset()
            request.addResource(with: .photo, data: data, options: nil)
            request.creationDate = Date()
        } completionHandler: { (success, _) in
            completion?(success)
        }
    }
    
    // 视频写入相册
    func saveVideoToLibrary(from filePath: URL,
                            completion: ((Bool, String?) -> Void)? = nil) {
        PHPhotoLibrary.shared().performChanges {
            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: filePath)
        } completionHandler: { (success, error) in
            completion?(success, error?.localizedFailureReason)
        }
    }
    
    // 本地文件写入相册
    func writeToLibrary(from fileURL: URL,
                        completion: ((Bool, String?) -> Void)? = nil) {
        guard FileManager.default.fileExists(atPath: fileURL.path) else {
            completion?(false, "File do not exist!")
            return
        }
        
        PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.creationRequestForAssetFromImage(atFileURL: fileURL)
        }, completionHandler: { success, error in
            completion?(success, error?.localizedFailureReason)
        })
    }
    
    func deleteFromLibrary(assetIdentifiers: [String], completion: ((Bool, String?) -> Void)?) {
        let deleteHandler = {
            let assetResult = PHAsset.fetchAssets(withLocalIdentifiers: assetIdentifiers, options: nil)
            guard assetResult.count > 0 else {
                completion?(false, "File don't exist")
                return
            }
            var assets = [PHAsset]()
            assetResult.enumerateObjects { asset, idx, _ in
                assets.append(asset)
            }
            PHPhotoLibrary.shared().performChanges({
                PHAssetChangeRequest.deleteAssets(assets as NSFastEnumeration)
            }, completionHandler: { success, error in
                if success {
                    NotificationCenter.default.post(name: .libraryVideoChangedNotify, object: nil)
                }
                completion?(success, error?.localizedFailureReason)
            })
        }
        
        handlerAfterAuthorization { [weak self] status in
            if status == .authorized || status == .limited {
                deleteHandler()
            } else {
                self?.showPhotoPermissionAlert()
            }
        }
    }
    
    /// 授权弹窗
    func handlerAfterAuthorization(completion: ((PHAuthorizationStatus) -> Void)?) {
        PHPhotoLibrary.requestAuthorization { (status) in
            DispatchQueue.main.async {
                completion?(status)
            }
        }
    }
    
    /// 授权失败弹窗
    func showPhotoPermissionAlert(from VC: UIViewController? = nil,
                                  message: String? = nil) {
        DispatchQueue.main.async {
            let fromVC = VC ?? UIApplication.topViewController
            let ac = UIAlertController(title: nil,
                                       message: message ?? "No album permission, allow us access to realize your personalized photo setting", preferredStyle: .alert)
            ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
            ac.addAction(UIAlertAction(title: "Setting", style: .default, handler: { _ in
                if let url = URL(string: UIApplication.openSettingsURLString),
                   UIApplication.shared.canOpenURL(url) {
                    UIApplication.shared.open(url)
                }
            }))
            fromVC?.present(ac, animated: true)
        }
    }
}

public extension PhotoManager {
    
    func saveToPhotoLibrary(image: UIImage, completionHandler: ((Bool) -> Void)?) {
        guard let data = image.pngData() else {
            completionHandler?(false)
            return
        }
        handlerAfterAuthorization { [weak self] status in
            if status == .authorized || status == .limited {
                self?.writeToLibrary(data: data, completion: completionHandler)
            } else {
                self?.showPhotoPermissionAlert()
            }
        }
    }
    
    // 保存多张壁纸
    func saveImages(_ urls: [String], authorCompletion: ((PHAuthorizationStatus) -> Void)? = nil,
                    completion: ((Bool, String?) -> Void)?) {
        let handler = { [weak self] in
            guard let self = self else { return }
            self.queue.async {
                var isSuccess = false
                let group = DispatchGroup()
                for url in urls {
                    group.enter()
                    self.multiTaskQueue.async { [weak self] in
                        self?.saveImage(url) { success, _ in
                            isSuccess = isSuccess || success
                            group.leave()
                        }
                    }
                }
                group.notify(queue: self.multiTaskQueue) {
                    completion?(isSuccess, isSuccess ? "Saved Successfully" : "Saved failed")
                }
            }
        }
        
        handlerAfterAuthorization { [weak self] status in
            authorCompletion?(status)
            if status == .authorized || status == .limited {
                handler()
            }
        }
    }
    
    // 保存壁纸图片
    func saveImage(_ url: String?,
                   completion: ((Bool, String?) -> Void)?) {
        let handler = { [weak self] in
            guard let self = self else { return }
            self.queue.async {
                self.fetchImageData(with: url) { [weak self] data in
                    guard let data = data else {
                        completion?(false, "Saved failed")
                        return
                    }
                    self?.writeToLibrary(data: data, completion: { success in
                        completion?(success, success ? "Saved Successfully" : "Saved failed")
                    })
                }
            }
        }
        
        handlerAfterAuthorization { [weak self] status in
            if status == .authorized || status == .limited {
                handler()
            } else {
                self?.showPhotoPermissionAlert()
            }
        }
    }
    
    func fetchImageData(with urlString: String?,
                    completion: ((Data?) -> Void)?) {
        guard let url = urlString, !url.isEmpty,
              let URL = URL(string: url) else {
            completion?(nil)
            return
        }
        
        ImageDownloader.default.downloadImage(with: URL, options: KingfisherParsedOptionsInfo(nil)) { result in
            switch result {
            case let .success(image):
                completion?(image.originalData)
            case .failure:
                completion?(nil)
            }
        }
    }
}

// MARK: PHPickerViewControllerDelegate
extension PhotoManager: PHPickerViewControllerDelegate {
    public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        
        /// 音频文件导入逻辑
        if importCompletionHandler != nil {
            picker.dismiss(animated: true) { [weak self] in
                self?.handlerPhotoPickerByImport(results: results)
            }
            return
        }
        
        let pickerDismissHandler = {
            if picker.navigationController?.viewControllers.count ?? 0 >= 2 {
                picker.navigationController?.popViewController(animated: true)
            }
            else {
                picker.dismiss(animated: true)
            }
        }
        
        /// 普通选择照片逻辑
        guard results.count > 0 else {
            pickerDismissHandler()
            return
        }
        
        fetchPhotos(with: results) { values in
            
        } completionHandler: { [weak self] images in
            guard let self = self else { return }
            
            if self.config.shouldCrop, images.count == 1 {
                DispatchQueue.main.async {
                    self.config.cropHandler?(picker, images[0])
                }
            } else {
                self.config.completionHandler?(images)
                DispatchQueue.main.async {
                    pickerDismissHandler()
                }
            }
        }
    }
    
    func fetchPhotos(with results: [PHPickerResult],
                     progressHandler: (([Int: UIImage]) -> Void)?,
                     completionHandler: (([UIImage]) -> Void)?) {
        // 用key，保证顺序
        var values = [Int: UIImage]()
        
        let group = DispatchGroup()
        let queue = DispatchQueue(label: "Queue_fetch_photos")
        
        for (index, result) in results.enumerated() {
            let itemProvider = result.itemProvider
            if itemProvider.hasItemConformingToTypeIdentifier(UTType.image.identifier) {
                group.enter()
                queue.async {
                    itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { (data, error) in
                        if let data = data,
                              var image = UIImage(data: data) {
                            image = image.kf.normalized
                            values[index] = image
                            progressHandler?([index: image])
                        }
                        group.leave()
                    }
                }
            }
        }
        
        group.notify(queue: queue) {
            var images = [UIImage]()
            for key in values.keys.sorted() {
                if let value = values[key] {
                    images.append(value)
                }
            }
            completionHandler?(images)
        }
    }
}
